package _07_映射.moudel;

import java.util.Objects;

/*
    自定义对象作为key,要同时重写equals方法和hashCode
    equals:用来判断两个key是否是相等
    hashCode:必须保证equals为true的两个key的哈希值一样

    实现hashCode，要利用person对象的所有字段信息进行混合计算哈希值
    实现equals,要利用person对象的所有字段信息进行比较

    如果不实现hashCode,那么算出来的索引就是不稳定的，同时也是为了让计算出来的索引均匀分配
    重写hashCode是为了保证两个相同的对象算出来的哈希值是一样的，而不是通过内存地址去计算哈希值，这样算出来两个一样的对象的哈希值不同
    当需要计算key的索引的时候，调用hashCode，拿到哈希值，去根据数组的table.length-1算出索引

    重写equals是为了保证当出现了哈希冲突时，
    去比较在一个节点上的多个不同类型的key是否相同，因为两个不同类型的key也可能算出一样的哈希值，所以不能用哈希值比较两个对象是否相等
    当出现哈希冲突时，比较同一个节点上多个key是否相同时调用equals

    hashCode相等的两个key不一定equals,因为不同类型的key计算出来的哈希值可能一样
    反过来就不一定，equals为true的两个对象哈希值一定相等
 */
public class Person {
    private int age;
    private float height;
    private String name;


    public Person(int age, float height, String name) {
        this.age = age;
        this.height = height;
        this.name = name;
    }


    @Override
    public boolean equals(Object o) {
        //内存地址一样
        if (this == o) return true;
        //类型不一样
        if (o == null || getClass() != o.getClass()) return false;

        //if(o == null || !(o instanceof Person)) return false; 不可靠，子类也会被当作一个Person
        //比较两个对象的成员变量
        Person person = (Person) o;
        return age == person.age && Float.compare(person.height, height) == 0 && Objects.equals(name, person.name);
    }

    //将自定义对象当成一个字符串，每一个属性当成字符 * 31 再相加每个字符 在赋值给hashCode
    //需要重复利用对象的每一个属性进行哈希值的计算
    @Override
    public int hashCode() {
        int hasCode = Integer.hashCode(age);
        hasCode = hasCode * 31 + Float.hashCode(height);
        hasCode = hasCode * 31 +(name != null ? name.hashCode() : 0);
        return hasCode;
    }
}
